﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace nameero.util
{
    class Heuristics
    {
        private const sbyte C1 = 3;
        private const sbyte C2 = 8;
        private const sbyte C3 = 6;
        private const sbyte C4 = 8;
        private const sbyte C5 = 6;
        private const sbyte C6 = 8;
        private const sbyte C7 = -1;
        private const sbyte C8 = 6;

        public byte pawns1;
        public byte pawns2;
        public byte kings1;
        public byte kings2;
        public byte safePawns1;
        public byte safePawns2;
        public byte safeKings1;
        public byte safeKings2;
        public byte moveablePawns1;
        public byte moveablePawns2;
        public byte moveableKings1;
        public byte moveableKings2;
        public byte distancePromotion1;
        public byte distancePromotion2;
        public byte unoccupied1;
        public byte unoccupied2;

        public Heuristics()
        {
            pawns1 = 12;
            pawns2 = 12;
            kings1 = 0;
            kings2 = 0;
            safePawns1 = 6;
            safePawns2 = 6;
            safeKings1 = 0;
            safeKings2 = 0;
            moveablePawns1 = 4;
            moveablePawns2 = 4;
            moveableKings1 = 0;
            moveableKings2 = 0;
            distancePromotion1 = 72;
            distancePromotion2 = 72;
            unoccupied1 = 0;
            unoccupied2 = 0;
        }

        public Heuristics(Heuristics old)
        {
            this.pawns1 = old.pawns1;
            this.pawns2 = old.pawns2;
            this.kings1 = old.kings1;
            this.kings2 = old.kings2;
            this.safePawns1 = old.safePawns1;
            this.safePawns2 = old.safePawns2;
            this.safeKings1 = old.safeKings1;
            this.safeKings2 = old.safeKings2;
            this.moveablePawns1 = old.moveablePawns1;
            this.moveablePawns2 = old.moveablePawns2;
            this.moveableKings1 = old.moveableKings1;
            this.moveableKings2 = old.moveableKings2;
            this.distancePromotion1 = old.distancePromotion1;
            this.distancePromotion2 = old.distancePromotion2;
            this.unoccupied1 = old.unoccupied1;
            this.unoccupied2 = old.unoccupied2;
        }

        public void evaluateBeforeMove(GameState state, Point from, Point to)
        {
            //kinganje
            if (to.row == 0 && state.getBoard()[from.row, from.col] == 1)
            {
                pawns1--;
                kings1++;
                unoccupied1--;
            }
            if (to.row == 7 && state.getBoard()[from.row, from.col] == -1)
            {
                pawns2--;
                kings2++;
                unoccupied2--;
            }

            //normalan potez
            if (state.getBoard()[from.row, from.col] == 1)
            {
                distancePromotion1 -= (byte)(to.row - from.row);
                if (isSafe(from))
                    safePawns1--;
                if (isSafe(to))
                    safePawns1++;
                if (canMove(state, from))
                    moveablePawns1--;
            }
            if (state.getBoard()[from.row, from.col] == 2)
            {
                if (to.row == 0)
                    unoccupied1--;
                if (from.row == 0 && to.row != 0)
                    unoccupied1++;
                if (isSafe(from))
                    safeKings1--;
                if (isSafe(to))
                    safeKings1++;
                if (canMove(state, from))
                    moveableKings1--;
            }
            if (state.getBoard()[from.row, from.col] == -1)
            {
                distancePromotion2 -= (byte)(from.row - to.row);
                if (isSafe(from))
                    safePawns2--;
                if (isSafe(to))
                    safePawns2++;
                if (canMove(state, from))
                    moveablePawns2--;
            }
            if (state.getBoard()[from.row, from.col] == -2)
            {
                if (to.row == 7)
                    unoccupied2--;
                if (from.row == 7 && to.row != 7)
                    unoccupied2++;
                if (isSafe(from))
                    safeKings2--;
                if (isSafe(to))
                    safeKings2++;
                if (canMove(state, from))
                    moveableKings2--;
            }

        }

        public void evaluateAfterMove(GameState state, Point p)
        {
            if (state.getBoard()[p.row, p.col] == 1)
            {
                if (canMove(state, p))
                    moveablePawns1++;
            }
            if (state.getBoard()[p.row, p.col] == 2)
            {
                if (canMove(state, p))
                    moveableKings1++;
            }
            if (state.getBoard()[p.row, p.col] == -1)
            {
                if (canMove(state, p))
                    moveablePawns2++;
            }
            if (state.getBoard()[p.row, p.col] == -2)
            {
                if (canMove(state, p))
                    moveableKings2++;
            }
        }

        public void evaluateErased(GameState state, Point p)
        {
            if (state.getBoard()[p.row, p.col] == 1)
            {
                pawns1--;
                if (canMove(state, p))
                    moveablePawns1--;
                distancePromotion1 -= (byte)p.row;
            }
            if (state.getBoard()[p.row, p.col] == -1)
            {
                pawns2--;
                if (canMove(state, p))
                    moveablePawns2--;
                distancePromotion2 -= (byte)(7 - p.row);
            }
            if (state.getBoard()[p.row, p.col] == 2)
            {
                kings1--;
                if (canMove(state, p))
                    moveableKings1--;
            }
            if (state.getBoard()[p.row, p.col] == -2)
            {
                kings2--;
                if (canMove(state, p))
                    moveableKings2--;
            }
        }
        private bool isSafe(Point p)
        {
            return p.row == 0 || p.row == 7 || p.col == 0 || p.col == 7;
        }

        private bool canMove(GameState state, Point p)
        {
            if (state.getBoard()[p.row, p.col] > 0 || state.getBoard()[p.row, p.col] == -2)
            {
                if (p.row > 0)
                {
                    if (p.col > 0 && state.getBoard()[p.row - 1, p.col - 1] == 0)
                        return true;
                    if (p.col < 7 && state.getBoard()[p.row - 1, p.col + 1] == 0)
                        return true;
                }
            }

            if (state.getBoard()[p.row, p.col] < 0 || state.getBoard()[p.row, p.col] == 2)
            {
                if (p.row < 7)
                {
                    if (p.col > 0 && state.getBoard()[p.row + 1, p.col - 1] == 0)
                        return true;
                    if (p.col < 7 && state.getBoard()[p.row + 1, p.col + 1] == 0)
                        return true;
                }
            }
            return false;
        }

        public int get3PhaseHeuristic(bool player1)
        {
            if (pawns1 > 3 && pawns2 > 3 && kings1 == 0 && kings2 == 0) //početna faza
            {
                int eval = C1 * (pawns1 - pawns2) + C2 * (distancePromotion2 - distancePromotion1) + C3 * (safePawns1 - safePawns2) + C5 * (moveablePawns1 - moveablePawns2);

                return player1 ? eval : -eval;
            }
            else if ((pawns1 + kings1) <= 3 || (pawns2 + kings2) <= 3) //završna faza
            {
                int eval = C2 * (kings1 - kings2) + C4 * (moveableKings1 - moveableKings2) + C6 * (distancePromotion2 - distancePromotion1);
                return player1 ? eval : -eval;
            }
            else
            {
                return getSimpleHeuristic(player1);
            }
        }

        public int getSimpleHeuristic(bool player1)
        {
            int eval = C1 * (pawns1 - pawns2) + C2 * (kings1 - kings2) + C3 * (safePawns1 - safePawns2) + C4 * (safeKings1 - safeKings2) + C5 * (moveablePawns1 - moveablePawns2) + C6 * (moveableKings1 - moveableKings2) + C7 * (distancePromotion1 - distancePromotion2) + C8 * (unoccupied1 - unoccupied2);
            return player1 ? eval : -eval;
        }
    }
}
